#ifndef WIDGET_H
#define WIDGET_H

#define STRING_DIRECT(x)          #x
#define STRING(x)                 STRING_DIRECT(x)
#define PRINT(x)                  std::cout << (x) << std::endl
#define ROUND(x)                  ((x)>0)?((int)((x)+0.5)):((int)((x)-0.5))
#define MESSAGE_ERROR(msg)        lblVersion->setText(version + msg)
#define MESSAGE_NORMAL()          lblVersion->setText(version)
#define AR3PC_ASSERT_ERROR(e, s)  if(!(e)){std::cout<<"AR3PC Error: "<<s<<std::endl;abort();}
#define TABPAGESNUM               6

#include <QWidget>
#include <QTimer>
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
#include <QTabWidget>
#include <QCheckBox>
#include <QSlider>
#include <QLineEdit>
#include <QTextEdit>
#include <QRadioButton>
#include "protocol.h"
#include "kinematic.hpp"
#include "file.hpp"
#ifdef USE_OPENCV
    #include "vision.h"
#endif
#ifdef USE_QTCHART
    #include <QtCharts>
#endif

class Widget : public QWidget
{
	Q_OBJECT
    // 全局变量
    QString version;
    bool isSPopen = false;  // 指示当前端口是否打开
    QStringList PreviousPortsName;  // 前一时刻的可用端口列表
    s16 PulseTargetTab1[6] = {0};  // Tab1目标脉冲步数
    s16 PulseTargetTab3[6] = {0};  // Tab3目标脉冲步数
    double JointAngleTab1[6] = {0};  // Tab1关节DH角度
    double JointAngleTab3[6] = {0};  // Tab3关节DH角度
    double PostureTab1[6] = {0};  // Tab1位姿
    double PostureTab3[6] = {0};  // Tab3位姿
    double _t;
    int KeyID;  //  用户界面按下的按键的编号
    FileRW datafile, pressfile;
    RobotArm ar3;
#ifdef USE_OPENCV
    Vision vision;
#endif
    // 主界面控件
    QTabWidget *tabWedget;
    QWidget *tabPages[TABPAGESNUM];
    QPushButton *btnOpen;
    QPushButton *btnEmergencyStop;  // 停止
    QCheckBox *ckbxEmergency;  // 是否紧急停止
    QLabel *lbltPort;
    QLabel *lbltBaudrate;
    QLabel *lblVersion;
    QComboBox *cbbxPort;
    QComboBox *cbbxBaudrate;
    Protocol *serialPort;
    QTimer *tmr100ms;
    // 页面1控件
    QLabel *lblt1JointName[12];  // 关节名称
    QLabel *lblt1Tuning1;  // 调节x100
    QLabel *lblt1Tuning2;  // 调节x10
    QLabel *lblt1Tuning3;  // 调节x1
    QCheckBox *ckbx1AutoSend;  // 自动发送
    QSlider *slid1Tuning1[6];  // 步进电机步数调节x100
    QSlider *slid1Tuning2[6];  // 步进电机步数调节x10
    QSlider *slid1Tuning3[6];  // 步进电机步数调节x1
    QLabel *lbl1Tuning1[6];  // 粗调步数1显示
    QLabel *lbl1Tuning2[6];  // 粗调步数2显示
    QLabel *lbl1Tuning3[6];  // 细调步数显示
    QLineEdit *ledt1PulseTarget[6];  // 步进电机的目标步数
    QLabel *lbl1JointAngle[6];  // 步进电机的目标角度(rad)
    QLabel *lbl1Posture[6];  // 末端目标位姿
    QPushButton *btn1FixLocation[6];  // 移动到固定位置
    // 页面2控件
    QLabel *lblt2Speed;
    QLabel *lblt2Accelerate;
    QLabel *lblt2JointName[6];  // 关节名称
    QPushButton *btn2JointCalibrate[8];  // 关节校准按键
    QPushButton *btn2ResetStep[7];  // 步数复位,将当前位置设置为脉冲起点
    QPushButton *btn2ReverseStep;  // 步数编辑框取负
    QCheckBox *ckbx2Reverse[6];  // 页面1给出的目标步数是否反向
    QLabel *lbl2CalibrateFlag[6];  // 是否校准成功
    QLineEdit *ledt2JointSpeed[6];  // 步进电机最大移动速度
    QLineEdit *ledt2JointAccelerate[6];  // 步进电机最大移动加速度
    QPushButton *btn2SetParam[6];  // 速度与加速度读取与写入,一键校准,复位
    QLineEdit *ledt2NegRadLim[6];  // 角度限制下限
    // 页面3控件
    QLabel *lblt3Posture[6];  // 位姿名称
    QLineEdit *ledt3Posture[6];  // 期望位姿输入
    QPushButton *btn3PostureDeltaPlus[6];  // 增加位姿按钮
    QPushButton *btn3PostureDeltaMinus[6];  // 减小位姿按钮
    QLineEdit *ledt3PostureDeltaValue[6];  // 位姿变化值
    QPushButton *btn3PulseDeltaPlus[6];  // 增加步数按钮
    QPushButton *btn3PulseDeltaMinus[6];  // 减小步数按钮
    QLineEdit *ledt3PulseDeltaValue[6];  // 步距值
    QPushButton *btn3PostureDeltaPlus6;  // 统一增加位姿按钮
    QPushButton *btn3PostureDeltaMinus6;  // 统一减小位姿按钮
    QCheckBox *ckbx3Options[4];  // 多个勾选框
    QLineEdit *ledt3PulseTarget[6];  // 步进电机的目标步数
    QLabel *lbl3JointAngle[6];  // 步进电机的目标角度(rad)
    QLabel *lbl3Posture[6];  // 末端目标位姿
    QPushButton *btn3Options[6];  // 多个功能按钮
    QLabel *lblt3Eff[3];  // 末端点坐标系名称
    QLineEdit *ledt3Eff[3];  // 末端点在坐标系6下的坐标
    // 页面4控件
    QCheckBox *ckbx4Options[5];  // 多个勾选框
    QPushButton *btn4Options[6];  // 多个按钮
    QPushButton *btn4UserInterface[4][6];  // 待检测的用户界面按键
    QLabel *lbl4Coordinates[7];  // 显示坐标
    QLabel *lblt4Coordinates[7];  // 坐标名称
    // 页面5控件
    QTextEdit *tedt5clipboard;
    QLineEdit *ledt5clipboard[6];
    QPushButton *btn5paste[3][9];
    // 页面6控件
#ifdef USE_QTCHART
    QLineSeries* line1;
    QChart* chart;
#endif

    // ui.cpp
	void Init_Mainform();
	void Init_Tab1();
	void Init_Tab2();
	void Init_Tab3();
    void Init_Tab4();
    void Init_Tab5();
    void Init_Tab6();
    // serialport.cpp
	void SerialPort_Open();
	void SerialPort_Close();
	void SerialPort_Scan();
	void SerialPort_Receive();
    // widget.cpp
    void Load_Control_data();  // 加载控件数据
    void Save_Control_data();  // 保存控件数据
    void Trajectory_Init();  // 轨迹规划初始化
    void Trajectory_Update();  // 轨迹规划更新
    void Security_Check();  // 安全检查

private slots:
	void Slot_tmr100ms_Tick();
	void Slot_btnOpen_Click();
    void Slot_btnEmergencyStop_Click();
    void Slot_slid1Tuning_valueChanged();
    void Slot_btn1FixLocation_Click();
    void Slot_ckbx2Reverse_Click();
    void Slot_btn2JointCalibrate_Click();
    void Slot_btn2ResetStep_Click();
    void Slot_btn2ReverseStep_Click();
    void Slot_btn2ReadSpeData_Click();
    void Slot_btn2ReadAccData_Click();
    void Slot_btn2ReadNegRadLim_Click();
    void Slot_btn2WriteSpeData_Click();
    void Slot_btn2WriteAccData_Click();
    void Slot_btn2WriteNegRadLim_Click();
    void Slot_btn3PostureDelta_Click();
    void Slot_btn3PostureDeltaPlus6_Click();
    void Slot_btn3PostureDeltaMinus6_Click();
    void Slot_btn3PulseDelta_Click();
    void Slot_btn3Reverse_Click();
    void Slot_btn3SynchroniseStep_Click();
    void Slot_btn3ReadEff_Click();
    void Slot_btn3WriteEff_Click();
    void Slot_btn4UserInterface_Click();
    void Slot_ckbx4Pressure_Click();
    void Slot_ckbx4WriteData_Click();
    void Slot_btn5Synchronise_Click();
#ifdef USE_OPENCV
    void Slot_ckbx4CameraTest();
    void Slot_btn4AddImageFromFile();
    void Slot_btn4Locate3d();
#endif

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
};

#endif
